home *** CD-ROM | disk | FTP | other *** search
- # Miro - an RSS based video player application
- # Copyright (C) 2005-2007 Participatory Culture Foundation
- #
- # This program is free software; you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation; either version 2 of the License, or
- # (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program; if not, write to the Free Software
- # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
- import os
-
- from xml.dom import minidom
- from xml.sax import saxutils
- from xml.parsers import expat
- from datetime import datetime
- from StringIO import StringIO
-
- import app
- import util
- import feed
- import views
- import prefs
- import config
- import folder
- import dialogs
- import eventloop
-
- from gtcache import gettext as _
- from gtcache import ngettext
-
- # =============================================================================
-
- class Exporter (object):
-
- def __init__(self):
- self.io = StringIO()
- self.currentFolder = None
-
- def exportSubscriptions(self):
- callback = lambda p: self.exportSubscriptionsTo(p)
- title = _("Export OPML File")
- app.delegate.askForSavePathname(title, callback, None, u"miro_subscriptions.opml")
-
- @eventloop.asIdle
- def exportSubscriptionsTo(self, pathname):
- now = datetime.now()
-
- self.io.write(u'<?xml version="1.0" encoding="utf-8" ?>\n')
- self.io.write(u'<!-- OPML generated by Miro v%s on %s -->\n' % (config.get(prefs.APP_VERSION), now.ctime()))
- self.io.write(u'<opml version="2.0">\n')
- self.io.write(u'\t<head>\n')
- self.io.write(u'\t\t<title>%s</title>\n' % os.path.basename(pathname))
- self.io.write(u'\t\t<dateCreated>%s</dateCreated>\n' % now.ctime())
- self.io.write(u'\t\t<docs>http://www.opml.org/spec2</docs>\n')
- self.io.write(u'\t</head>\n')
- self.io.write(u'\t<body>\n')
-
- tabOrder = util.getSingletonDDBObject(views.channelTabOrder)
- for tab in tabOrder.getAllTabs():
- if tab.isChannelFolder():
- self._openFolderEntry(tab.obj)
- elif tab.isFeed():
- self._writeFeedEntry(tab.obj)
-
- if self.currentFolder is not None:
- self._closeFolderEntry()
-
- self.io.write(u'\t</body>\n')
- self.io.write(u'</opml>\n')
-
- f = open(pathname, "w")
- f.write(self.io.getvalue().encode('utf-8'))
- f.close()
-
- def _openFolderEntry(self, folder):
- if self.currentFolder is not None:
- self._closeFolderEntry()
- self.currentFolder = folder
- self.io.write(u'\t\t<outline text=%s>\n' % saxutils.quoteattr(folder.getTitle()))
-
- def _closeFolderEntry(self):
- self.io.write(u'\t\t</outline>\n')
-
- def _writeFeedEntry(self, thefeed):
- if (self.currentFolder is not None) and (thefeed.getFolder() is None):
- self._closeFolderEntry()
- self.currentFolder = None
- if self.currentFolder is None:
- spacer = u'\t\t'
- else:
- spacer = u'\t\t\t'
-
- # FIXME - RSSFeedImpl items should be of type "rss", but
- # it's not clear what type other things should be. We
- # mark them as "mirofeed"--this should get changed if there
- # are issues.
- if isinstance(thefeed.getActualFeed(), feed.RSSFeedImpl):
- feedtype = u'type="rss"'
- else:
- feedtype = u'type="mirofeed"'
-
- self.io.write(u'%s<outline %s text=%s xmlUrl=%s />\n' % (spacer, feedtype, saxutils.quoteattr(thefeed.getTitle()), saxutils.quoteattr(thefeed.getURL())))
-
- # =============================================================================
-
- class Importer (object):
-
- def __init__(self):
- self.currentFolder = None
- self.ignoredFeeds = 0
- self.importedFeeds = 0
-
- def importSubscriptions(self):
- callback = lambda p: self.importSubscriptionsFrom(p)
- title = _("Import OPML File")
- app.delegate.askForOpenPathname(title, callback, None,
- _("OPML Files"), ['opml'])
-
- @eventloop.asIdle
- def importSubscriptionsFrom(self, pathname, showSummary = True):
- f = open(pathname, "r")
- content = f.read()
- f.close()
-
- try:
- dom = minidom.parseString(content)
- root = dom.documentElement
- body = root.getElementsByTagName("body").pop()
- self._walkOutline(body)
- dom.unlink()
- if showSummary:
- self.showImportSummary()
- except expat.ExpatError:
- self.showXMLError()
-
- def showXMLError(self):
- title = _(u"OPML Import failed")
- message = _(u"The selected OPML file appears to be invalid. Import was interrupted.")
- dialog = dialogs.MessageBoxDialog(title, message)
- dialog.run()
-
- def showImportSummary(self):
- title = _(u"OPML Import summary")
- message = ngettext(u"Successfully imported %d feed.", u"Successfully imported %d feeds.", self.importedFeeds) % self.importedFeeds
- if self.ignoredFeeds > 0:
- message += "\n"
- message += ngettext(u"Skipped %d feed already present.", u"Skipped %d feeds already present.", self.ignoredFeeds) % self.ignoredFeeds
- dialog = dialogs.MessageBoxDialog(title, message)
- dialog.run()
-
- def _walkOutline(self, node):
- try:
- children = node.childNodes
- for child in children:
- if hasattr(child, 'getAttribute'):
- if child.hasAttribute("xmlUrl"):
- self._handleFeedEntry(child)
- else:
- self._handlerFolderEntry(child)
- self.currentFolder = None
- except Exception, e:
- print e
- pass
-
- def _handleFeedEntry(self, entry):
- url = entry.getAttribute("xmlUrl")
- f = feed.getFeedByURL(url)
- if f is None:
- f = feed.Feed(url, False)
- title = entry.getAttribute("text")
- if title is not None and title != '':
- f.setTitle(title)
- if self.currentFolder is not None:
- f.setFolder(self.currentFolder)
- f.blink()
- self.importedFeeds += 1
- else:
- self.ignoredFeeds += 1
-
- def _handlerFolderEntry(self, entry):
- title = entry.getAttribute("text")
- self.currentFolder = folder.ChannelFolder(title)
- self._walkOutline(entry)
-
- # =============================================================================
-